package game

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"server/GoUtil"
	"server/MergeConst"
	"server/db"
	"server/gamedata"
	"strconv"
	"strings"
	"time"

	"server/pkg/github.com/name5566/leaf/timer"
)

type LimitEventPeriod struct {
	StartCronID cron.EntryID
	EndTimer    *timer.Timer
	StartTime   int32
	EndTime     int32
	Duration    int32
	CronStr     string
	AddTimes    int32
}

func NewLimitEventData(dataName string, dbName string, player *Player) *PlayerLimitData {
	act := &PlayerLimitData{
		PlayerData: NewPlayerData(dataName, player),
		MDbName:    dbName,
	}

	return act
}

func CreateLimiteEventData(ID int32, dataName string, player *Player) PlayerDataModule {
	var data PlayerDataModule
	if ID == 1 {
		data = &PlayerChestRainData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Chest_Rain", player)}
	}
	if ID == 2 {
		data = &PlayerSuperEmiterData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Super_Emiter", player)}
	}
	if ID == 3 {
		data = &PlayerStarRainData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Star_Rain", player)}
	}
	if ID == 4 {
		data = &PlayerHighRollerData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_High_Roller", player)}
	}
	if ID == 5 {
		data = &PlayerSuperOrderData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Super_Order", player)}
	}
	if ID == 6 {
		data = &PlayerSceneSprintData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Scene_Sprint", player)}
	}
	if ID == 7 {
		data = &PlayerCardFestivalData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Card_Festival", player)}
	}
	if ID == 8 {
		data = &PlayerDoubleHitData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Double_Hit", player)}
	}
	if ID == 9 {
		data = &PlayerCardSwapData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Card_Swap", player)}
	}
	if ID == 10 {
		data = &PlayerPetRobberData{PlayerLimitData: NewLimitEventData(dataName, "t_Limit_Pet_Robber", player)}
	}

	return data
}

type LimiteEventManager struct {
	MStatus           int32
	CronList          map[int][]string
	IsSettle          int32
	IsLoadDB          bool
	MUpdateNotifyList []int32
	McronSave         *cron.Cron
	McronSaveID       cron.EntryID
	RobotCronID       cron.EntryID
	RobotCronID10s    cron.EntryID
	m_MapCronEntryIDs map[int][]*LimitEventPeriod
	Mdispatr          *timer.Dispatcher
	IsHighRoll        bool
}

func (p *LimiteEventManager) GetLimitDataNameById(id int32) string {
	LimitDataMap := make(map[int32]string)
	LimitDataMap[1] = "PlayerChestRainData"
	LimitDataMap[2] = "PlayerSuperEmiterData"
	LimitDataMap[3] = "PlayerStarRainData"
	LimitDataMap[4] = "PlayerHighRollerData"
	LimitDataMap[5] = "PlayerSuperOrderData"
	LimitDataMap[6] = "PlayerSceneSprintData"
	LimitDataMap[7] = "PlayerCardFestivalData"
	LimitDataMap[8] = "PlayerDoubleHitData"
	LimitDataMap[9] = "PlayerCardSwapData"
	LimitDataMap[10] = "PlayerPetRobberData"

	return LimitDataMap[id]
}

func (p *LimiteEventManager) SaveDataFromDB(Key interface{}) bool {

	return true
}

func (p *LimiteEventManager) GetSunDayZero() int64 {
	timeStamp := time.Now().Unix()
	t := time.Unix(timeStamp, 0).Local()
	delta := int(t.Weekday()*3600*24) + t.Hour()*3600 + t.Minute()*60 + t.Second()
	return int64(timeStamp) - int64(delta)
}

func (p *LimiteEventManager) GetLimitDataStatus(id int) *LimitEventPeriod {
	timeStamp := time.Now().Unix()
	keys := p.m_MapCronEntryIDs[id]
	for i := 0; i < len(keys); i++ {
		if timeStamp >= int64(keys[i].StartTime) && timeStamp < int64(keys[i].EndTime) {
			return keys[i]
		}
	}
	return nil
}

func (p *LimiteEventManager) GetIsHighRollerPersion() bool {
	return p.IsHighRoll
}

// 1.宝箱雨
func (p *LimiteEventManager) InitManager() {
	// 0 11 20 12 *
	p.IsHighRoll = false
	p.m_MapCronEntryIDs = map[int][]*LimitEventPeriod{}
	c := cron.New()
	LimiteCfg := gamedata.GetConfigByName("LimiteEvent")
	WeekZero := p.GetSunDayZero()
	timeStamp := time.Now().Unix()

	p.Mdispatr = timer.NewDispatcher(10)
	for i := 0; i < LimiteCfg.NumRecord(); i++ {
		record := LimiteCfg.Record(i).(*gamedata.LimiteEvent)
		startStrr := record.StartTime
		starts := strings.Split(startStrr, "|")

		DurStrr := record.Duration
		Durs := strings.Split(DurStrr, "|")

		AddTimesStrr := record.AddTimes
		ats := strings.Split(AddTimesStrr, "|")

		p.m_MapCronEntryIDs[record.Id] = []*LimitEventPeriod{}
		for n := 0; n < len(starts); n++ {
			LEP := &LimitEventPeriod{}
			start := starts[n]
			dur, _ := strconv.Atoi(Durs[n])
			addt, _ := strconv.Atoi(ats[n])
			LEP.StartCronID, _ = c.AddFunc(start, func() {
				fmt.Println("Next: UTC", c.Entry(LEP.StartCronID).Next.Unix())
				fmt.Println("CronStr:" + LEP.CronStr)
				cur := int32(time.Now().Unix())
				LEP.StartTime = int32(cur)
				LEP.EndTime = int32(cur) + int32(dur)
				if record.Id == 9 {
					if G_GameLogicPtr.M_SvrGlobal.LimitCardSwapTime < LEP.StartTime {
						card4Cfg, str4 := gamedata.GetRandomDifferenceSet(4, G_GameLogicPtr.M_SvrGlobal.Limit4CardExclude)
						card5Cfg, str5 := gamedata.GetRandomDifferenceSet(5, G_GameLogicPtr.M_SvrGlobal.Limit5CardExclude)
						G_GameLogicPtr.M_SvrGlobal.Limit4Card = int32(card4Cfg.Id)
						G_GameLogicPtr.M_SvrGlobal.Limit5Card = int32(card5Cfg.Id)
						G_GameLogicPtr.M_SvrGlobal.Limit4CardExclude = str4
						G_GameLogicPtr.M_SvrGlobal.Limit5CardExclude = str5
						G_GameLogicPtr.M_SvrGlobal.LimitCardSwapTime = LEP.StartTime
						db.FormatAllMemUpdateDb(&G_GameLogicPtr.M_SvrGlobal, "t_server_global_data", "Id")
					}
				}
				GoUtil.CallEvent(MergeConst.OpenNewLimitEvent, []interface{}{record.Id, cur, cur + int32(dur), record.Type})
				if record.Id == 4 {
					p.IsHighRoll = true
				}
				go func() {
					LeafTimer := p.Mdispatr.AfterFunc(time.Duration(dur)*time.Second, func() {
						if record.Id == 4 {
							p.IsHighRoll = false
						}
					})
					LEP.EndTimer = LeafTimer

					(<-p.Mdispatr.ChanTimer).Cb()
				}()
			})
			LEP.Duration = int32(dur)
			LEP.CronStr = start
			LEP.AddTimes = int32(addt)
			p.m_MapCronEntryIDs[record.Id] = append(p.m_MapCronEntryIDs[record.Id], LEP)
		}
	}
	c.Start()
	for k, v := range p.m_MapCronEntryIDs {
		// record := LimiteCfg.Index(k).(*gamedata.LimiteEvent)
		key := k
		for i := 0; i < len(v); i++ {
			Schedule := c.Entry(v[i].StartCronID).Schedule
			Next := Schedule.Next(time.Unix(WeekZero, 0))
			// fmt.Println("Next.Unix():" + strconv.Itoa(int(Next.Unix())))
			value := v[i]
			if timeStamp >= Next.Unix() && timeStamp < Next.Unix()+int64(value.Duration) {
				fmt.Println("CronStr:" + value.CronStr)
				if key == 4 {
					p.IsHighRoll = true
				}
				if key == 9 {
					if G_GameLogicPtr.M_SvrGlobal.LimitCardSwapTime < int32(Next.Unix()) {
						card4Cfg, str4 := gamedata.GetRandomDifferenceSet(4, G_GameLogicPtr.M_SvrGlobal.Limit4CardExclude)
						card5Cfg, str5 := gamedata.GetRandomDifferenceSet(5, G_GameLogicPtr.M_SvrGlobal.Limit5CardExclude)
						G_GameLogicPtr.M_SvrGlobal.Limit4Card = int32(card4Cfg.Id)
						G_GameLogicPtr.M_SvrGlobal.Limit5Card = int32(card5Cfg.Id)
						G_GameLogicPtr.M_SvrGlobal.Limit4CardExclude = str4
						G_GameLogicPtr.M_SvrGlobal.Limit5CardExclude = str5
						G_GameLogicPtr.M_SvrGlobal.LimitCardSwapTime = int32(Next.Unix())
						db.FormatAllMemUpdateDb(&G_GameLogicPtr.M_SvrGlobal, "t_server_global_data", "Id")
					}
				}
				go func() {
					delta := Next.Unix() + int64(value.Duration) - timeStamp
					LeafTimer := p.Mdispatr.AfterFunc(time.Duration(delta)*time.Second, func() {
						if key == 4 {
							p.IsHighRoll = false
						}
					})
					value.EndTimer = LeafTimer
					value.StartTime = int32(Next.Unix())
					value.EndTime = int32(Next.Unix()) + int32(value.Duration)
					(<-p.Mdispatr.ChanTimer).Cb()
				}()
			} else {

			}
		}

	}

}
